package ar.uba.fi.tonyvaliente.tree;

/**
 * Representa un nodo del árbol.
 * Puede ser inner o leaf.
 * 
 * Se parametrizan los tipos de las claves y valores.
 * 
 * @author santiago
 *
 * @param <K> tipo de las claves.
 * @param <V> tipo de los valores.
 */
public abstract class BPlusTreeNode <K extends Comparable<K>,V> {

	/**
	 * Referencia al nodo padre.
	 */
	private Reference<K, V> parent;
	
	/**
	 * Referencia al nodo, necesaria para setear como parent al hacer split
	 * y para realizar la lista de nodos a actualizar.
	 */
	private Reference<K, V> thisReference;
	
	protected BPlusTree<K, V> tree;
	
	/**
	 * Cantidad actual de elementos en el nodo.
	 */
	protected Integer cantidadElementos;
	
	/**
	 * Máxima cantidad de elementos por nodo.
	 */
	protected Integer maxCantidadElementos;
	
	protected BPlusTreeNode(Reference<K, V> parent, BPlusTree<K, V> tree, Integer maxCantidadElementos) {
		super();
		this.parent = parent;
		this.tree = tree;
		this.maxCantidadElementos = maxCantidadElementos;
	}
	
	protected BPlusTreeNode(Reference<K, V> parent, Integer maxCantidadElementos) {
		super();
		this.parent = parent;
		this.maxCantidadElementos = maxCantidadElementos;
	}
	
	protected BPlusTreeNode(Reference<K, V> parent) {
		super();
		this.parent = parent;
	}
	
	protected BPlusTreeNode(BPlusTree<K, V> tree) {
		super();
		this.tree = tree;
	}
	
	/**
	 * Añade el par clave valor al árbol.
	 * Retorna un indicador para saber si es necesario hacer un split.
	 * 
	 * @param key
	 * @param value
	 * @return
	 */
	protected abstract AddResult<K, V> add(K key, V value) throws BPlusTreeException;
	
	/**
	 * Dada una clave devuelve su valor asociado.
	 * 
	 * @param key
	 * @return
	 */
	protected abstract V get(K key) throws BPlusTreeException;
	
	protected Reference<K, V> getParent() {
		return parent;
	}

	protected void setParent(Reference<K, V> parent) {
		this.parent = parent;
	}

	protected Integer getCantidadElementos() {
		return cantidadElementos;
	}

	protected void setCantidadElementos(Integer cantidadElementos) {
		this.cantidadElementos = cantidadElementos;
	}

	protected Integer getMaxCantidadElementos() {
		return maxCantidadElementos;
	}

	protected void setMaxCantidadElementos(Integer maxCantidadElementos) {
		this.maxCantidadElementos = maxCantidadElementos;
	}

	protected BPlusTree<K, V> getTree(){
		return this.tree;
	}
	
	protected void setTree(BPlusTree<K, V> tree){
		this.tree = tree;
	}
	
	protected Reference<K, V> getThisReference() {
		return thisReference;
	}

	protected void setThisReference(Reference<K, V> thisReference) {
		this.thisReference = thisReference;
	}	
	
	/**
	 * Representa el resultado de la operación add.
	 * @author santiago
	 *
	 */
	public class AddResult<K extends Comparable<K>, V>{
		K key;
		Reference<K, V> leftReference;
		Reference<K, V> rightReference;
		
		public K getKey() {
			return key;
		}
		public void setKey(K key) {
			this.key = key;
		}
		public Reference<K, V> getLeftReference() {
			return leftReference;
		}
		public void setLeftReference(Reference<K, V> leftReference) {
			this.leftReference = leftReference;
		}
		public Reference<K, V> getRightReference() {
			return rightReference;
		}
		public void setRightReference(Reference<K, V> rightReference) {
			this.rightReference = rightReference;
		}
		
		
	}

}
